package com.recommend;

import cn.hutool.core.collection.CollectionUtil;

import java.util.*;

/**
 * 作用描述 -皮尔逊
 *
 * @Author: Eric
 */

public class Recommend {

    /**
     * 在给定userName的情况下，计算其他用户和它的距离并排序
     */
    private Map<Double, String> computeNearestNeighbor(String userId, UserSet userSet) {
        // 降序排序，treemap默认是升序排序
        Map<Double, String> distances = new TreeMap<>(new Comparator<Double>() {
            @Override
            public int compare(Double o1, Double o2) {
                if (o1.compareTo(o2) == 1) {
                    return -1;
                } else if (o1.compareTo(o2) == -1) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });

        // 根据用户id获取用户信息
        UserSet.User u1 = userSet.getUser(userId);

        // 遍历收集所有用户对应收藏的信息及次数集合
        for (int i = 0; i < userSet.users.size(); i++) {

            // 获取一个user对象
            UserSet.User u2 = userSet.getUser(i);

            // 如果传来的用户id与集合中循环的i个用户的名字不匹配
            if (!u2.userId.equals(userId)) {

                // 皮尔逊相关系数计算
                double distance = pearson_dis(u2.list, u1.list);
                distances.put(distance, u2.userId);
            }

        }
        System.out.println("distance => " + distances);
        return distances;
    }

    /**
     * 计算2个打分序列间的pearson距离
     *
     * @param rating1 循环的用户推荐信息集合
     * @param rating2 根据传入用户获取的推荐信息集合
     * @return
     */
    private double pearson_dis(List<UserSet.RInfo> rating1, List<UserSet.RInfo> rating2) {

        // 记录相同命中次数
        int n = 0;

        for (int i = 0; i < rating1.size(); i++) {
            UserSet.RInfo key1 = rating1.get(i);
            for (int j = 0; j < rating2.size(); j++) {
                UserSet.RInfo key2 = rating2.get(j);
                // 推荐信息id相同
                if (key1.id.equals(key2.id)) {
                    // 命中一次
                    n += 1;
                }
            }
        }

        // 没命中一次
        if (n == 0) {
            return 0;
        }

        // 根号
        double denominator = Math.sqrt(rating1.size() * rating2.size());
        if (denominator == 0) {
            return 0;
        } else {
            // 计算相似度
            return n / denominator;
        }
    }

    // 推荐方法
    public List<UserSet.RInfo> recommend(String userId, UserSet user) {

        // 实例化一个存储推荐信息集合
        List<UserSet.RInfo> recommendations = new ArrayList<>();

        //找到最近邻
        Map<Double, String> distances = computeNearestNeighbor(userId, user);
        if (CollectionUtil.isEmpty(distances)) {
            return recommendations;
        }
        Iterator<String> iterator = distances.values().iterator();
        String nearest = iterator.next();

        System.out.println("nearest -> " + nearest);

        //找到最近邻，计算推荐
        UserSet.User neighborRatings = user.getUser(nearest);
        System.out.println("neighborRatings -> " + neighborRatings.list);

        UserSet.User userRatings = user.getUser(userId);
        System.out.println("userRatings -> " + userRatings.list);

        for (UserSet.RInfo artist : neighborRatings.list) {
            if (userRatings.find(artist.id) == null) {
                recommendations.add(artist);
            }
        }
        Collections.sort(recommendations);
        System.out.println("recommendations -> " + recommendations.toString());
        return recommendations;
    }


}
